package main

import (
	"bufio"
	"errors"
	"fmt"

	. "gitee.com/cloudapex/Ghost/utd"

	//"io/ioutil"
	"io"
	"os"
	"strings"
	"time"
)

var allRegistEnums = make([]string, 0, 5)

func MakeProtoGD() error {
	iPaths := ""
	tempFileName := fmt.Sprintf("./%s.%s", FILE_NAME_PROTO, FILE_PROTO_SUFFIX)
	if len(vImportPaths) > 0 {
		iPaths = "-I=" + strings.Join(vImportPaths, " -I=")
	}
	if outStr, err := Sys.ExecCmd("protoc_v3", true, "--go_out=.", tempFileName, "-I=.", iPaths); err != nil {
		return errors.New(fmt.Sprintf("protoc_v3 --go_out=. %s -I=. %s,命令执行失败:\n%s%s\n", tempFileName, iPaths, outStr, err.Error()))
	}

	os.Remove(TargetFile)                                 // 移除老的
	file, _ := os.OpenFile(TargetFile, os.O_CREATE, 0666) // 创建新的
	defer file.Close()

	WriteGdFileHead(file)                        // 写头部
	WriteGdFileMsgEnum(file)                     // 写枚举
	if err := WriteGdFileMsg(file); err != nil { // 写消息单元 移除old文件
		return err
	}
	WriteGdFileMsgReg(file) // 写注册信息 最后再写

	os.Remove("./" + FILE_NAME_PROTO + FILE_PB_PROTO_SUFFIX) //删除.pb.go文件
	return nil
}

/////////////////////////////////////////////////////////////////////////////
// 							写文件头部
/////////////////////////////////////////////////////////////////////////////
var strHead_ = `extends Node
class_name %s # add to AutoLoad list by name must be 'G%s'
################################################################################
### Copyright:cloud
### Author:cloudapex@126.com
### Version:2.1
### Date:%s
### Description:协议包的最终文件 支持构造 序列化/反序列化 自动注册
### Note: THIS FILE IS AUTOMATICALLY GENERATED BY GPACK TOOL, DO NOT EDIT!!!
################################################################################
`

func WriteGdFileHead(file *os.File) {
	str := fmt.Sprintf(strHead_, vPacketName, vPacketName, time.Now().Format("2006-01-02"))
	file.WriteString(str)
}

func WriteGdFileMsgEnum(file *os.File) {

	str := `enum {
`
	first := true
	for _, value := range MsgTypeLinesAll {
		value = strings.Replace(value, "//", "#", 1)
		if strings.Contains(value, "=") {
			if first {
				first = false
			} else {
				file.WriteString("}\n")
			}
			file.WriteString(str)
		}
		file.WriteString("	" + value + "\n")
	}

	file.WriteString("}\n")
}

//============================生成一条注册信息 写入注册信息=======================
var strGdFomatRegMsg = `	GNetMsic.reg_net_message(%-16s	funcref(self,"New%s"))
`
var strGdFomatRegStc = `	GNetMsic.reg_net_structr(%-16s	funcref(self,"New%s"))
`

func MakeOneGdRegMsg(msgName string) string {
	msgType := MakeOneMsgType(msgName)
	return fmt.Sprintf(strGdFomatRegMsg, msgType+",", msgName)
}

func WriteGdFileMsgReg(file *os.File) {
	str := `func _enter_tree():
`
	file.WriteString(str)
	for _, value := range allRegistEnums {
		file.WriteString(value + "\n")
	}
	for _, value := range InterStructNamesAll {
		file.WriteString(fmt.Sprintf(strGdFomatRegStc, "\""+value+"\",", value))
	}
	for _, value := range MsgStructNamesAll {
		file.WriteString(MakeOneGdRegMsg(value))
	}
	file.WriteString("#end\n")
}

func ParseMsgClassField(msgName, line string) (string, string) {
	fields := strings.Fields(line)
	defTyp, defVal := "", fields[1]
	switch defVal {
	case "bool":
		defVal = "false"
	case "int32", "uint32", "int64", "uint64":
		defVal = "0"
	case "float32", "float64":
		defVal = "0.0"
	case "string":
		defVal = "\"\""
	default:
		if strings.HasPrefix(defVal, "[]") {
			defVal = "[]"
		} else if strings.HasPrefix(defVal, "map") {
			defVal = "{}"
		} else if strings.HasPrefix(defVal, "*") {
			defVal = "null"
		} else { // for enum
			defVal = "0"
		}
	}
	if fields[0] == "Head" && strings.HasPrefix(msgName, "Msg") {
		defVal = fmt.Sprintf("GNetMsic.NewMsgHead(%s)", MakeOneMsgType(msgName))
	}
	typVal := fields[1]
	if strings.HasPrefix(typVal, "[]*") {
		fieds := strings.Split(typVal, ".")
		typVal = "[]*" + fieds[len(fieds)-1]
	} else if strings.HasPrefix(typVal, "map") {
		mkv := strings.Split(string([]byte(typVal)[4:]), "]")
		mva := mkv[1]
		if strings.HasPrefix(mkv[1], "*") && strings.Contains(typVal, ".") {
			fieds := strings.Split(mkv[1], ".")
			mva = "*" + fieds[len(fieds)-1]
		}
		mkey := strings.Split(fields[len(fields)-2], "\"")[1]
		mval := strings.Split(fields[len(fields)-1], "\"")[1]
		typVal = fmt.Sprintf("map[%s|%s]", mkv[0]+","+mkey, mva+","+mval)
		typVal = strings.Replace(typVal, ",", "-", -1)
	} else if strings.HasPrefix(typVal, "*") {
		if strings.Contains(typVal, ".") {
			fieds := strings.Split(typVal, ".")
			typVal = "*" + fieds[len(fieds)-1]
		} else {
			defTyp = strings.Replace(typVal, "*", "", 1)
		}
	} else if strings.Contains(line, "enum=") { // for enum
		if strings.Contains(line, "rep") {
			typVal = "[]enum"
		} else {
			typVal = "enum"
		}
	}
	tagstr := typVal + "," + strings.Split(fields[2], "\"")[1]
	prop := fmt.Sprintf("[\"%s\", \"%s\"]", fields[0], tagstr)
	return fmt.Sprintf("	var	%-20s :%s= %s\n", fields[0], defTyp, defVal), prop
}
func WriteGdFileMsgClass(file *os.File, msgname, tags string) {
	str1 := `
	static func struct_name() -> String: return "%s"
	static func struct_tags() -> Array:
		return [%s]
	func GetHead() -> NetMsic.MsgHead: 	return Head
	func SetHead(head:NetMsic.MsgHead): Head = head
func New%s() -> %s: return %s.new()
`
	str2 := `
	static func struct_name() -> String: return "%s"
	static func struct_tags() -> Array:
		return [%s]
func New%s() -> %s: return %s.new()
`
	if strings.HasPrefix(msgname, "Msg") && !strings.Contains(msgname, "_") {
		file.WriteString(fmt.Sprintf(str1, msgname, tags, msgname, msgname, msgname))
	} else {
		file.WriteString(fmt.Sprintf(str2, msgname, tags, msgname, msgname, msgname))
	}
	file.WriteString("#end\n")
}
func WriteGdFileMsg(file *os.File) error {
	f, err := os.Open("./" + FILE_NAME_PROTO + FILE_PB_PROTO_SUFFIX)
	if err != nil {
		return err
	}
	defer f.Close()

	bNeed := false
	enumName := ""
	msgName := ""
	msgFields := make([]string, 0, 5)
	enumRegist := make([]string, 0, 5)
	// 按行读取
	buf := bufio.NewReader(f)
	for {
		line, err := buf.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				line += "\n"
				file.WriteString(line)
				return nil
			}
			return err
		}
		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}
		if strings.Contains(line, "type ") {
			switch {
			case strings.Contains(line, " int32"):
				fields := strings.Fields(line)
				enumName = fields[1]
				file.WriteString("enum " + strings.Replace(ModifyMsgEnumName2(enumName), "_", "", 1) + " {\n")
				bNeed = true
				continue
			case strings.Contains(line, " struct"):
				fields := strings.Fields(line)
				msgName = fields[1]
				file.WriteString("class " + msgName + ":\n")
				bNeed = true
				continue
			}
		} else if line == ")" {
			bNeed, enumName = false, ""
			file.WriteString("}\n")
			allRegistEnums = append(allRegistEnums, strings.Join(enumRegist, "\n"))
			enumRegist = make([]string, 0, 5)
		} else if line == "}" {
			bNeed = false
			if msgName != "" {
				WriteGdFileMsgClass(file, msgName, strings.Join(msgFields, ",\n\t\t\t\t"))
				if !strings.HasPrefix(msgName, "Msg") {
					InterStructNamesAll = append(InterStructNamesAll, msgName)
				}
				msgName = ""
				msgFields = make([]string, 0, 5)
			}
		}
		if bNeed {
			switch {
			case enumName != "" && strings.Contains(line, enumName):
				fields := strings.Fields(line)
				ModifyMsgEnumName2(enumName)
				//fmt.Printf("%#v\n", fields)
				fields[0] = strings.TrimPrefix(fields[0], strings.Split(enumName, "_")[0]+"_")
				file.WriteString(fmt.Sprintf("	%-28s = %s\n", fields[0], fields[3]))
				enumRegist = append(enumRegist, fmt.Sprintf("	GNetMsic.reg_enum_string(%-q, %s, %q)", strings.Replace(ModifyMsgEnumName2(enumName), "_", "", 1)+",", fields[3], fields[0]))
			case msgName != "":
				varstr, tagstr := ParseMsgClassField(msgName, line)
				file.WriteString(varstr)
				msgFields = append(msgFields, tagstr)
				//fmt.Printf("%#v", fields)
			}
		}
	}
}
